In [1]:
%pip install zipline-reloaded
%pip install quandl
%pip install pyfolio-reloaded
Requirement already satisfied: zipline-reloaded in c:\aj_msds\.venv\lib\site-packages (3.1.1)
Requirement already satisfied: numpy>=1.26.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.3.3)
Requirement already satisfied: pandas<3.0,>=1.3.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.3.3)
Requirement already satisfied: alembic>=0.7.7 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.17.1)
Requirement already satisfied: bcolz-zipline>=1.2.6 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.13.0)
Requirement already satisfied: bottleneck>=1.0.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.6.0)
Requirement already satisfied: click>=4.0.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (8.3.0)
Requirement already satisfied: empyrical-reloaded>=0.5.7 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (0.5.12)
Requirement already satisfied: h5py>=2.7.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.15.1)
Requirement already satisfied: intervaltree>=2.1.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.1.0)
Requirement already satisfied: iso3166>=2.1.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.1.1)
Requirement already satisfied: iso4217>=1.6.20180829 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.14.20250512)
Requirement already satisfied: lru-dict>=1.1.4 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.3.0)
Requirement already satisfied: multipledispatch>=0.6.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.0.0)
Requirement already satisfied: networkx>=2.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.5)
Requirement already satisfied: numexpr>=2.6.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.14.1)
Requirement already satisfied: patsy>=0.4.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.0.2)
Requirement already satisfied: python-dateutil>=2.4.2 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.9.0.post0)
Requirement already satisfied: pytz>=2018.5 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2025.2)
Requirement already satisfied: requests>=2.9.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.32.5)
Requirement already satisfied: scipy>=0.17.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.16.2)
Requirement already satisfied: six>=1.10.0 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.17.0)
Requirement already satisfied: sqlalchemy>=2 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (2.0.44)
Requirement already satisfied: statsmodels>=0.6.1 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (0.14.5)
Requirement already satisfied: tables>=3.4.3 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (3.10.2)
Requirement already satisfied: toolz>=0.8.2 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (1.1.0)
Requirement already satisfied: exchange-calendars>=4.2.4 in c:\aj_msds\.venv\lib\site-packages (from zipline-reloaded) (4.11.2)
Requirement already satisfied: tzdata>=2022.7 in c:\aj_msds\.venv\lib\site-packages (from pandas<3.0,>=1.3.0->zipline-reloaded) (2025.2)
Requirement already satisfied: Mako in c:\aj_msds\.venv\lib\site-packages (from alembic>=0.7.7->zipline-reloaded) (1.3.10)
Requirement already satisfied: typing-extensions>=4.12 in c:\aj_msds\.venv\lib\site-packages (from alembic>=0.7.7->zipline-reloaded) (4.15.0)
Requirement already satisfied: packaging in c:\aj_msds\.venv\lib\site-packages (from bcolz-zipline>=1.2.6->zipline-reloaded) (25.0)
Requirement already satisfied: colorama in c:\aj_msds\.venv\lib\site-packages (from click>=4.0.0->zipline-reloaded) (0.4.6)
Requirement already satisfied: peewee<3.17.4 in c:\aj_msds\.venv\lib\site-packages (from empyrical-reloaded>=0.5.7->zipline-reloaded) (3.17.3)
Requirement already satisfied: pyluach>=2.3.0 in c:\aj_msds\.venv\lib\site-packages (from exchange-calendars>=4.2.4->zipline-reloaded) (2.3.0)
Requirement already satisfied: korean_lunar_calendar>=0.3.1 in c:\aj_msds\.venv\lib\site-packages (from exchange-calendars>=4.2.4->zipline-reloaded) (0.3.1)
Requirement already satisfied: sortedcontainers<3.0,>=2.0 in c:\aj_msds\.venv\lib\site-packages (from intervaltree>=2.1.0->zipline-reloaded) (2.4.0)
Requirement already satisfied: charset_normalizer<4,>=2 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (3.4.3)
Requirement already satisfied: idna<4,>=2.5 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (2.5.0)
Requirement already satisfied: certifi>=2017.4.17 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.9.1->zipline-reloaded) (2025.8.3)
Requirement already satisfied: greenlet>=1 in c:\aj_msds\.venv\lib\site-packages (from sqlalchemy>=2->zipline-reloaded) (3.2.4)
Requirement already satisfied: py-cpuinfo in c:\aj_msds\.venv\lib\site-packages (from tables>=3.4.3->zipline-reloaded) (9.0.0)
Requirement already satisfied: blosc2>=2.3.0 in c:\aj_msds\.venv\lib\site-packages (from tables>=3.4.3->zipline-reloaded) (3.11.0)
Requirement already satisfied: ndindex in c:\aj_msds\.venv\lib\site-packages (from blosc2>=2.3.0->tables>=3.4.3->zipline-reloaded) (1.10.0)
Requirement already satisfied: msgpack in c:\aj_msds\.venv\lib\site-packages (from blosc2>=2.3.0->tables>=3.4.3->zipline-reloaded) (1.1.2)
Requirement already satisfied: platformdirs in c:\aj_msds\.venv\lib\site-packages (from blosc2>=2.3.0->tables>=3.4.3->zipline-reloaded) (4.4.0)
Requirement already satisfied: MarkupSafe>=0.9.2 in c:\aj_msds\.venv\lib\site-packages (from Mako->alembic>=0.7.7->zipline-reloaded) (3.0.3)
Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 25.2 -> 25.3
[notice] To update, run: python.exe -m pip install --upgrade pip
Requirement already satisfied: quandl in c:\aj_msds\.venv\lib\site-packages (3.7.0)
Requirement already satisfied: pandas>=0.14 in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.3.3)
Requirement already satisfied: numpy>=1.8 in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.3.3)
Requirement already satisfied: requests>=2.7.0 in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.32.5)
Requirement already satisfied: inflection>=0.3.1 in c:\aj_msds\.venv\lib\site-packages (from quandl) (0.5.1)
Requirement already satisfied: python-dateutil in c:\aj_msds\.venv\lib\site-packages (from quandl) (2.9.0.post0)
Requirement already satisfied: six in c:\aj_msds\.venv\lib\site-packages (from quandl) (1.17.0)
Requirement already satisfied: more-itertools in c:\aj_msds\.venv\lib\site-packages (from quandl) (10.8.0)
Requirement already satisfied: pytz>=2020.1 in c:\aj_msds\.venv\lib\site-packages (from pandas>=0.14->quandl) (2025.2)
Requirement already satisfied: tzdata>=2022.7 in c:\aj_msds\.venv\lib\site-packages (from pandas>=0.14->quandl) (2025.2)
Requirement already satisfied: charset_normalizer<4,>=2 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (3.4.3)
Requirement already satisfied: idna<4,>=2.5 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (2.5.0)
Requirement already satisfied: certifi>=2017.4.17 in c:\aj_msds\.venv\lib\site-packages (from requests>=2.7.0->quandl) (2025.8.3)
Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 25.2 -> 25.3
[notice] To update, run: python.exe -m pip install --upgrade pip
Requirement already satisfied: pyfolio-reloaded in c:\aj_msds\.venv\lib\site-packages (0.9.9)
Requirement already satisfied: numpy>=1.26.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (2.3.3)
Requirement already satisfied: pandas<3.0,>=1.5.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (2.3.3)
Requirement already satisfied: ipython>=3.2.3 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (9.6.0)
Requirement already satisfied: matplotlib>=1.4.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (3.10.6)
Requirement already satisfied: pytz>=2014.10 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (2025.2)
Requirement already satisfied: scipy>=0.14.0 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (1.16.2)
Requirement already satisfied: scikit-learn>=0.16.1 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (1.7.2)
Requirement already satisfied: seaborn>=0.7.1 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (0.13.2)
Requirement already satisfied: empyrical-reloaded>=0.5.9 in c:\aj_msds\.venv\lib\site-packages (from pyfolio-reloaded) (0.5.12)
Requirement already satisfied: python-dateutil>=2.8.2 in c:\aj_msds\.venv\lib\site-packages (from pandas<3.0,>=1.5.0->pyfolio-reloaded) (2.9.0.post0)
Requirement already satisfied: tzdata>=2022.7 in c:\aj_msds\.venv\lib\site-packages (from pandas<3.0,>=1.5.0->pyfolio-reloaded) (2025.2)
Requirement already satisfied: bottleneck>=1.3.0 in c:\aj_msds\.venv\lib\site-packages (from empyrical-reloaded>=0.5.9->pyfolio-reloaded) (1.6.0)
Requirement already satisfied: peewee<3.17.4 in c:\aj_msds\.venv\lib\site-packages (from empyrical-reloaded>=0.5.9->pyfolio-reloaded) (3.17.3)
Requirement already satisfied: colorama in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.4.6)
Requirement already satisfied: decorator in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (5.2.1)
Requirement already satisfied: ipython-pygments-lexers in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (1.1.1)
Requirement already satisfied: jedi>=0.16 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.19.2)
Requirement already satisfied: matplotlib-inline in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.1.7)
Requirement already satisfied: prompt_toolkit<3.1.0,>=3.0.41 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (3.0.52)
Requirement already satisfied: pygments>=2.4.0 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (2.19.2)
Requirement already satisfied: stack_data in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (0.6.3)
Requirement already satisfied: traitlets>=5.13.0 in c:\aj_msds\.venv\lib\site-packages (from ipython>=3.2.3->pyfolio-reloaded) (5.14.3)
Requirement already satisfied: wcwidth in c:\aj_msds\.venv\lib\site-packages (from prompt_toolkit<3.1.0,>=3.0.41->ipython>=3.2.3->pyfolio-reloaded) (0.2.14)
Requirement already satisfied: parso<0.9.0,>=0.8.4 in c:\aj_msds\.venv\lib\site-packages (from jedi>=0.16->ipython>=3.2.3->pyfolio-reloaded) (0.8.5)
Requirement already satisfied: contourpy>=1.0.1 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (1.3.3)
Requirement already satisfied: cycler>=0.10 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (4.60.1)
Requirement already satisfied: kiwisolver>=1.3.1 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (1.4.9)
Requirement already satisfied: packaging>=20.0 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (25.0)
Requirement already satisfied: pillow>=8 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (11.3.0)
Requirement already satisfied: pyparsing>=2.3.1 in c:\aj_msds\.venv\lib\site-packages (from matplotlib>=1.4.0->pyfolio-reloaded) (3.2.5)
Requirement already satisfied: six>=1.5 in c:\aj_msds\.venv\lib\site-packages (from python-dateutil>=2.8.2->pandas<3.0,>=1.5.0->pyfolio-reloaded) (1.17.0)
Requirement already satisfied: joblib>=1.2.0 in c:\aj_msds\.venv\lib\site-packages (from scikit-learn>=0.16.1->pyfolio-reloaded) (1.5.2)
Requirement already satisfied: threadpoolctl>=3.1.0 in c:\aj_msds\.venv\lib\site-packages (from scikit-learn>=0.16.1->pyfolio-reloaded) (3.6.0)
Requirement already satisfied: executing>=1.2.0 in c:\aj_msds\.venv\lib\site-packages (from stack_data->ipython>=3.2.3->pyfolio-reloaded) (2.2.1)
Requirement already satisfied: asttokens>=2.1.0 in c:\aj_msds\.venv\lib\site-packages (from stack_data->ipython>=3.2.3->pyfolio-reloaded) (3.0.0)
Requirement already satisfied: pure-eval in c:\aj_msds\.venv\lib\site-packages (from stack_data->ipython>=3.2.3->pyfolio-reloaded) (0.2.3)
Note: you may need to restart the kernel to use updated packages.
[notice] A new release of pip is available: 25.2 -> 25.3
[notice] To update, run: python.exe -m pip install --upgrade pip
In [42]:
from zipline import run_algorithm
from zipline.api import (
    attach_pipeline,
    calendars,
    pipeline_output,
    date_rules,
    time_rules,
    set_commission,
    set_slippage,
    order_target_percent,
    get_open_orders,
    schedule_function
)
from datetime import datetime
import pytz
import pyfolio as pf
import matplotlib.pyplot as plt
import quandl
import pandas as pd
import zipline
In [ ]:
import os

quandl_api_key = 'API_KEY_HERE'
quandl.ApiConfig.api_key = quandl_api_key
# Set environment variable for Quandl
os.environ['QUANDL_API_KEY'] = 'API_KEY_HERE'
In [4]:
!zipline ingest -b quandl
Downloading WIKI Prices table from Quandl
Merging daily equity files:
[2025-11-02T17:31:05-0600-INFO][zipline.data.bundles.core]
 Ingesting quandl
[2025-11-02T17:31:05-0600-INFO][zipline.data.bundles.quandl]
 Downloading WIKI metadata.
[2025-11-02T17:32:17-0600-INFO][zipline.data.bundles.quandl]
 Parsing raw data.
[2025-11-02T17:32:39-0600-INFO][zipline.data.bundles.quandl]
 Generating asset metadata.
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\data\bundles\quandl.py:107: FutureWarning: The provided callable <function min at 0x00000288B4185DA0> is currently using SeriesGroupBy.min. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string "min" instead.
  data = data.groupby(by="symbol").agg({"date": [np.min, np.max]})
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\data\bundles\quandl.py:107: FutureWarning: The provided callable <function max at 0x00000288B4185D00> is currently using SeriesGroupBy.max. In a future version of pandas, the provided callable will be used directly. To keep current behavior pass the string "max" instead.
  data = data.groupby(by="symbol").agg({"date": [np.min, np.max]})
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\assets\asset_writer.py:321: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  mappings.groupby(["symbol", "country_code"], group_keys=False).apply(
c:\AJ_MSDS\.venv\Lib\site-packages\zipline\data\bcolz_daily_bars.py:341: UserWarning: Ignoring 1 values because they are out of bounds for uint32:
             open  high   low  close        volume  ex_dividend  split_ratio
2011-04-11  1.79  1.84  1.55    1.7  6.674913e+09          0.0          1.0
  winsorise_uint32(raw_data, invalid_data_behavior, "volume", *OHLC)
[2025-11-02T17:34:43-0600-INFO][zipline.data.bundles.quandl]
 Parsing split data.
[2025-11-02T17:34:43-0600-INFO][zipline.data.bundles.quandl]
 Parsing dividend data.
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=67, ex_date=2017-11-09, amount=0.620
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=93, ex_date=2017-11-09, amount=0.240
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=161, ex_date=2017-11-09, amount=0.110
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=283, ex_date=2017-11-09, amount=0.415
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=298, ex_date=2017-11-09, amount=1.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=318, ex_date=2017-11-09, amount=0.330
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=434, ex_date=2017-11-09, amount=0.110
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=516, ex_date=1996-05-30, amount=0.310
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=524, ex_date=2017-11-09, amount=0.050
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=556, ex_date=2017-11-09, amount=0.075
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=578, ex_date=2017-11-09, amount=0.160
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=605, ex_date=2017-11-09, amount=0.040
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=666, ex_date=1990-03-26, amount=0.140
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=694, ex_date=1990-03-27, amount=0.100
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=723, ex_date=2017-11-09, amount=1.620
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=758, ex_date=2017-11-09, amount=0.500
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=788, ex_date=2017-11-09, amount=0.060
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=859, ex_date=1995-05-09, amount=0.100
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=904, ex_date=2017-11-09, amount=0.135
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=975, ex_date=2017-11-09, amount=0.030
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1057, ex_date=2017-11-09, amount=0.250
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1088, ex_date=1990-03-26, amount=0.240
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1091, ex_date=2017-11-09, amount=0.075
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1111, ex_date=1993-03-04, amount=0.070
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1172, ex_date=2017-11-09, amount=0.130
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1209, ex_date=2017-11-09, amount=0.010
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1322, ex_date=1995-05-25, amount=0.150
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1441, ex_date=2017-11-09, amount=1.500
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1525, ex_date=2017-11-09, amount=0.090
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1600, ex_date=2015-07-06, amount=16.500
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1642, ex_date=2017-11-09, amount=0.270
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1748, ex_date=2017-11-09, amount=0.740
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1876, ex_date=2017-11-09, amount=0.120
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1922, ex_date=2017-11-09, amount=0.040
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=1947, ex_date=1990-03-26, amount=0.150
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2098, ex_date=2017-11-09, amount=0.200
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2118, ex_date=2014-11-06, amount=0.050
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2120, ex_date=2017-11-09, amount=0.110
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2149, ex_date=2017-11-09, amount=0.330
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2204, ex_date=2017-11-09, amount=0.320
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2220, ex_date=2017-11-09, amount=0.660
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2281, ex_date=2017-11-09, amount=0.450
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2389, ex_date=2017-11-09, amount=0.140
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2441, ex_date=2017-11-09, amount=0.215
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2517, ex_date=2017-11-09, amount=0.080
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2582, ex_date=2017-11-09, amount=0.780
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2622, ex_date=2017-11-09, amount=0.390
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2662, ex_date=2015-01-14, amount=0.750
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2754, ex_date=2000-12-27, amount=0.250
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2754, ex_date=2009-09-11, amount=0.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2754, ex_date=2009-12-11, amount=0.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2754, ex_date=2010-03-11, amount=0.420
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2754, ex_date=2010-12-15, amount=0.180
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2766, ex_date=2017-11-09, amount=0.320
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2798, ex_date=2017-11-09, amount=0.065
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2817, ex_date=1992-03-03, amount=0.300
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2824, ex_date=2017-11-09, amount=0.120
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2843, ex_date=2017-11-09, amount=0.150
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2857, ex_date=2011-09-07, amount=0.410
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=2968, ex_date=1990-03-26, amount=0.100
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=3005, ex_date=1990-03-26, amount=0.070
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=3078, ex_date=2014-05-12, amount=0.060
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=3117, ex_date=2017-11-09, amount=0.430
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=3138, ex_date=2010-08-16, amount=0.060
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Couldn't compute ratio for dividend sid=3145, ex_date=2017-11-09, amount=0.050
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=501, ex_date=2006-01-03, amount=41.560
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=1557, ex_date=2007-07-02, amount=88.530
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=1632, ex_date=2000-07-13, amount=181.000
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=1657, ex_date=2013-09-30, amount=21.355
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=1775, ex_date=1994-12-01, amount=76.000
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=1776, ex_date=1996-11-04, amount=36.708
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=2455, ex_date=2016-10-03, amount=25.611
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=2687, ex_date=2008-06-26, amount=10.000
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=2900, ex_date=2007-07-02, amount=88.530
[2025-11-02T17:34:48-0600-WARNING][zipline.data.adjustments]
 Dividend ratio <= 0 for dividend sid=3088, ex_date=2015-04-27, amount=31.291
In [45]:
start = pd.Timestamp('1998-01-01')
end = pd.Timestamp('2018-12-31')
live_start_date = '2006-02-27'

tickers = ['AAPL', 'WMT', 'XOM',
            #'GOOGL', 'MSFT', 'NVDA', 'AMD', 'INTC', 'ORCL',
            # 'BIDU',
            # 'COST', 'PG', 'KO', 'PEP',
            # 'CME', 'AVGO', 'WMT', 'JNJ', 'XOM',
            # 'HD', 
            # 'EQIX', 
            # 'ABBV', 'SCHD', 'PFF', 'VWO', 'VEA, 'GLD', 'FXY','FXE','VNQ', 'TLT',
            ]
In [46]:
from zipline.api import symbol

def initialize(context):
    context.universe = [symbol(s) for s in tickers]
    # History window
    context.history_window = 20

    # Size of our portfolio
    context.stocks_to_hold = 10

    # Schedule the daily trading routine for once per month
    schedule_function(handle_data, date_rules.month_start(), time_rules.market_close())

def month_perf(ts):
    perf = (ts[-1] / ts[0]) - 1
    return perf

def handle_data(context, data):
    # Get history for all the stocks.
    hist = data.history(context.universe, "close", context.history_window, "1d")

    # This creates a table of percent returns, in order.
    perf_table = hist.apply(month_perf).sort_values(ascending=False)

    # Make buy list of the top N stocks
    buy_list = perf_table[:context.stocks_to_hold]

    # The rest will not be held.
    the_rest = perf_table[context.stocks_to_hold:]

    # Place target buy orders for top N stocks.
    for stock, perf in buy_list.items():
        stock_weight = 1 / context.stocks_to_hold

        # Place order
        if data.can_trade(stock):
            order_target_percent(stock, stock_weight)

    # Make sure we are flat the rest.
    for stock, perf in the_rest.items():
        # Place order
        if data.can_trade(stock):
            order_target_percent(stock, 0.0)

def analyze(context, perf):
    fig = plt.figure(figsize=(12, 8))

    # First chart
    ax = fig.add_subplot(311)
    ax.set_title('Strategy Results')
    ax.plot(perf.index, perf['portfolio_value'], linestyle='-',
                label='Equity Curve', linewidth=3.0)


    ax.legend()
    ax.grid(False)

    # Second chart
    ax = fig.add_subplot(312)
    ax.plot(perf.index, perf['gross_leverage'],
            label='Exposure', linestyle='-', linewidth=1.0)
    ax.legend()
    ax.grid(True)

    #Use PyFolio to generate a performance report
    returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
    pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
                          live_start_date=live_start_date, round_trips=True)
In [47]:
algo1_momentum_results = run_algorithm(start=start, end=end,
                        initialize=initialize, analyze=analyze,
                        handle_data=handle_data,
                        capital_base=10000,
                        data_frequency = 'daily', bundle='quandl')
C:\Users\Sujala\AppData\Local\Temp\tmpe964z5zr\ipykernel_11880\1736499118.py:15: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  perf = (ts[-1] / ts[0]) - 1
C:\Users\Sujala\AppData\Local\Temp\tmpe964z5zr\ipykernel_11880\1736499118.py:15: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  perf = (ts[-1] / ts[0]) - 1
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '7.725%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '3.613%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '5.189%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
Start date1998-01-02
End date2018-12-31
In-sample months97
Out-of-sample months154
In-sample Out-of-sample All
Annual return 7.725% 3.613% 5.189%
Cumulative returns 83.131% 57.688% 188.776%
Annual volatility 8.056% 5.591% 6.657%
Sharpe ratio 0.96 0.66 0.79
Calmar ratio 0.58 0.31 0.39
Stability 0.73 0.93 0.96
Max drawdown -13.356% -11.657% -13.356%
Omega ratio 1.18 1.14 1.16
Sortino ratio 1.40 0.96 1.15
Skew -0.58 0.22 -0.30
Kurtosis 9.11 11.90 11.56
Tail ratio 1.13 1.03 1.08
Daily value at risk -0.984% -0.69% -0.818%
Gross leverage 0.30 0.30 0.30
Daily turnover 0.85% 0.282% 0.511%
Worst drawdown periods Net drawdown in % Peak date Valley date Recovery date Duration
0 13.36 2000-04-03 2002-07-23 2004-04-15 1054
1 11.66 2008-06-05 2009-03-09 2009-11-17 379
2 7.71 2015-02-17 2016-01-20 2017-05-03 577
3 5.74 2007-12-26 2008-03-10 2008-04-21 84
4 5.37 2012-09-21 2013-04-18 2013-12-26 330
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
  ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
Stress Events mean min max
Dotcom 0.02% -1.28% 1.52%
Lehman -0.08% -2.96% 1.37%
9/11 0.11% -1.20% 1.11%
US downgrade/European Debt Crisis 0.01% -1.51% 1.13%
Fukushima 0.01% -0.84% 0.58%
US Housing -0.08% -0.73% 0.81%
EZB IR Event -0.01% -0.36% 0.53%
Aug07 0.01% -1.47% 1.02%
Mar08 0.13% -0.76% 1.41%
Sept08 -0.19% -2.96% 1.37%
2009Q1 -0.05% -1.23% 1.04%
2009Q2 0.09% -0.82% 1.65%
Flash Crash -0.17% -1.02% 0.94%
Apr14 0.08% -0.32% 0.79%
Oct14 0.04% -0.51% 0.60%
Fall2015 -0.06% -1.19% 1.38%
Low Volatility Bull Market 0.03% -1.36% 1.17%
GFC Crash 0.00% -2.96% 3.76%
Recovery 0.03% -1.51% 1.13%
New Normal 0.01% -1.19% 1.38%
Top 10 long positions of all time max
sid
WMT 19.88%
XOM 19.59%
AAPL 19.38%
Top 10 short positions of all time max
sid
Top 10 positions of all time max
sid
WMT 19.88%
XOM 19.59%
AAPL 19.38%
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn("Negative price detected, ignoring for" "round-trip.")
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn("Negative price detected, ignoring for" "round-trip.")
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn("Negative price detected, ignoring for" "round-trip.")
Summary stats All trades Short trades Long trades
Total number of round_trips 958.00 87.00 871.00
Percent profitable 0.69 0.54 0.70
Winning round_trips 657.00 47.00 610.00
Losing round_trips 301.00 40.00 261.00
Even round_trips 0.00 0.00 0.00
PnL stats All trades Short trades Long trades
Total profit $5824.21 $-339.46 $6163.67
Gross profit $11487.42 $1713.98 $9773.44
Gross loss $-5663.21 $-2053.44 $-3609.77
Profit factor $2.03 $0.83 $2.71
Avg. trade net profit $6.08 $-3.90 $7.08
Avg. winning trade $17.48 $36.47 $16.02
Avg. losing trade $-18.81 $-51.34 $-13.83
Ratio Avg. Win:Avg. Loss $0.93 $0.71 $1.16
Largest winning trade $212.44 $112.43 $212.44
Largest losing trade $-408.10 $-408.10 $-213.59
Duration stats All trades Short trades Long trades
Avg duration 402 days 03:53:32.943632568 880 days 05:41:22.758620688 354 days 09:49:48.289322616
Median duration 212 days 12:00:00 438 days 01:00:00 210 days 23:00:00
Longest duration 3028 days 01:00:00 3028 days 01:00:00 1328 days 01:00:00
Shortest duration 1 days 00:00:00 9 days 00:00:00 1 days 00:00:00
Return stats All trades Short trades Long trades
Avg returns all round_trips 0.04% -0.01% 0.04%
Avg returns winning 0.11% 0.17% 0.10%
Avg returns losing -0.11% -0.23% -0.09%
Median returns all round_trips 0.04% 0.02% 0.04%
Median returns winning 0.07% 0.14% 0.07%
Median returns losing -0.05% -0.13% -0.04%
Largest winning trade 1.80% 0.56% 1.80%
Largest losing trade -1.59% -1.59% -1.55%
Symbol stats AAPL WMT XOM
Avg returns all round_trips 0.05% 0.04% 0.02%
Avg returns winning 0.13% 0.07% 0.08%
Avg returns losing -0.15% -0.03% -0.11%
Median returns all round_trips 0.04% 0.03% 0.04%
Median returns winning 0.09% 0.05% 0.07%
Median returns losing -0.07% -0.02% -0.05%
Largest winning trade 1.80% 0.46% 0.27%
Largest losing trade -1.59% -0.13% -0.98%
Profitability (PnL / PnL total) per name
symbol
AAPL 51.69%
WMT 36.24%
XOM 12.08%
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [49]:
# moving average strategy
from zipline.api import order_target, record, symbol
from zipline.finance import commission, slippage

def initialize(context):
    context.universe = [symbol(s) for s in tickers]
    context.history_window_long = 300
    context.history_window_short = 100
    context.i = 0

    # Set commission and slippage
    context.set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1.0))
    context.set_slippage(slippage.VolumeShareSlippage())
    schedule_function(handle_data, date_rules.every_day(), time_rules.market_close())


def handle_data(context, perf):
    # Skip first 300 days to get full windows
    context.i += 1
    if context.i < 300:
        return
    rebalance(context, perf)

def rebalance(context, perf):
    for asset in context.universe:
        if not perf.can_trade(asset):
            continue

        short_mavg = perf.history(asset, 'price', context.history_window_short, '1d').mean()
        long_mavg = perf.history(asset, 'price', context.history_window_long, '1d').mean()

        if short_mavg > long_mavg:
            weight = 1.0 / len(context.universe)
            order_target_percent(asset, weight)
        elif short_mavg < long_mavg:
            order_target_percent(asset, 0.0)

def analyze(context, perf):
    import matplotlib.pyplot as plt

    fig = plt.figure()
    ax1 = fig.add_subplot(211)
    perf['portfolio_value'].plot(ax=ax1)
    ax1.set_ylabel("Portfolio value (USD)")

    plt.show()
    #Use PyFolio to generate a performance report
    returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
    pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
                          live_start_date=live_start_date, round_trips=True)
In [50]:
algo2_dma_results = run_algorithm(start=start, end=end,
                        initialize=initialize, analyze=analyze,
                        handle_data=handle_data,
                        capital_base=10000,
                        data_frequency = 'daily', bundle='quandl')
No description has been provided for this image
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '2.738%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '8.169%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '6.029%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
Start date1998-01-02
End date2018-12-31
In-sample months97
Out-of-sample months154
In-sample Out-of-sample All
Annual return 2.738% 8.169% 6.029%
Cumulative returns 24.562% 173.936% 241.218%
Annual volatility 25.853% 15.909% 20.349%
Sharpe ratio 0.24 0.57 0.39
Calmar ratio 0.04 0.38 0.09
Stability 0.17 0.89 0.73
Max drawdown -68.795% -21.591% -68.795%
Omega ratio 1.05 1.12 1.08
Sortino ratio 0.32 0.83 0.55
Skew -0.83 0.06 -0.65
Kurtosis 11.67 10.84 14.99
Tail ratio 1.03 0.99 0.99
Daily value at risk -3.233% -1.968% -2.532%
Gross leverage 0.97 0.90 0.93
Daily turnover 55.059% 51.315% 52.707%
Worst drawdown periods Net drawdown in % Peak date Valley date Recovery date Duration
0 68.80 2000-04-03 2002-09-27 2009-10-20 2492
1 19.36 2018-01-18 2018-03-27 NaT NaN
2 16.93 2012-09-21 2013-02-04 2014-07-07 467
3 16.19 2000-01-20 2000-02-25 2000-03-21 44
4 15.35 1998-08-21 1998-08-31 1998-11-06 56
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\matplotlib\dates.py:449: UserWarning: no explicit representation of timezones available for np.datetime64
  d = d.astype('datetime64[us]')
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
  ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
Stress Events mean min max
Dotcom 0.05% -3.91% 5.09%
Lehman -0.08% -4.26% 4.73%
9/11 0.14% -3.68% 2.10%
US downgrade/European Debt Crisis 0.03% -5.24% 4.00%
Fukushima -0.03% -3.47% 1.33%
US Housing 0.00% 0.00% 0.00%
EZB IR Event -0.04% -1.18% 1.75%
Aug07 0.03% -4.86% 3.41%
Mar08 0.44% -2.46% 4.91%
Sept08 -0.23% -4.26% 4.73%
2009Q1 -0.11% -2.48% 1.49%
2009Q2 0.09% -1.18% 1.34%
Flash Crash -0.32% -2.14% 2.61%
Apr14 0.27% -1.08% 2.60%
Oct14 0.14% -1.72% 1.97%
Fall2015 -0.05% -2.04% 2.70%
Low Volatility Bull Market 0.07% -4.50% 3.83%
GFC Crash 0.06% -5.09% 9.92%
Recovery 0.05% -5.24% 4.00%
New Normal 0.01% -10.14% 3.75%
Top 10 long positions of all time max
sid
XOM 162.89%
WMT 106.03%
AAPL 70.83%
Top 10 short positions of all time max
sid
XOM -101.61%
AAPL -65.30%
WMT -43.43%
Top 10 positions of all time max
sid
XOM 162.89%
WMT 106.03%
AAPL 70.83%
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn("Negative price detected, ignoring for" "round-trip.")
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn("Negative price detected, ignoring for" "round-trip.")
Summary stats All trades Short trades Long trades
Total number of round_trips 5108.00 1985.00 3123.00
Percent profitable 0.51 0.45 0.55
Winning round_trips 2600.00 894.00 1706.00
Losing round_trips 2508.00 1091.00 1417.00
Even round_trips 0.00 0.00 0.00
PnL stats All trades Short trades Long trades
Total profit $-22608.05 $-10279.02 $-12329.02
Gross profit $217735.46 $139266.06 $78469.40
Gross loss $-240343.50 $-149545.08 $-90798.42
Profit factor $0.91 $0.93 $0.86
Avg. trade net profit $-4.43 $-5.18 $-3.95
Avg. winning trade $83.74 $155.78 $46.00
Avg. losing trade $-95.83 $-137.07 $-64.08
Ratio Avg. Win:Avg. Loss $0.87 $1.14 $0.72
Largest winning trade $2779.44 $2779.44 $1077.15
Largest losing trade $-13563.72 $-8505.15 $-13563.72
Duration stats All trades Short trades Long trades
Avg duration 44 days 11:29:35.332811276 43 days 05:57:22.216624685 45 days 06:16:01.383285302
Median duration 3 days 00:00:00 1 days 00:00:00 7 days 00:00:00
Longest duration 1162 days 00:00:00 1162 days 00:00:00 372 days 00:00:00
Shortest duration 0 days 21:00:00 0 days 21:00:00 0 days 21:00:00
Return stats All trades Short trades Long trades
Avg returns all round_trips -0.02% -0.03% -0.01%
Avg returns winning 0.44% 0.78% 0.26%
Avg returns losing -0.49% -0.70% -0.33%
Median returns all round_trips 0.00% -0.03% 0.01%
Median returns winning 0.16% 0.32% 0.10%
Median returns losing -0.16% -0.27% -0.10%
Largest winning trade 8.69% 8.69% 5.14%
Largest losing trade -38.94% -31.07% -38.94%
Symbol stats AAPL WMT XOM
Avg returns all round_trips -0.01% -0.01% -0.03%
Avg returns winning 0.98% 0.25% 0.31%
Avg returns losing -1.00% -0.28% -0.40%
Median returns all round_trips -0.00% 0.00% 0.00%
Median returns winning 0.41% 0.12% 0.10%
Median returns losing -0.43% -0.12% -0.11%
Largest winning trade 8.36% 3.37% 8.69%
Largest losing trade -31.07% -4.57% -38.94%
Profitability (PnL / PnL total) per name
symbol
XOM 97.13%
AAPL 9.04%
WMT -6.17%
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [51]:
def initialize_mean_reversion(context):
    
    context.universe = [symbol(s) for s in tickers]
    context.lookback = 20
    context.z_entry = 1.0
    context.z_exit = 0.25
    schedule_function(mean_reversion_rebalance, date_rules.every_day(), time_rules.market_close())

def mean_reversion_rebalance(context, data):
    price_history = data.history(context.universe, 'price', context.lookback, '1d')
    mean_price = price_history.mean()
    std_price = price_history.std()

    for asset in context.universe:
        if not data.can_trade(asset):
            continue

        z_score = (data.current(asset, 'price') - mean_price[asset]) / std_price[asset]
        if z_score < -context.z_entry:
            order_target_percent(asset, 0.25)  # go long
        elif z_score > context.z_entry:
            order_target_percent(asset, -0.25)  # go short
        elif abs(z_score) < context.z_exit:
            order_target_percent(asset, 0)

def analyze(context, perf):
    import matplotlib.pyplot as plt

    fig = plt.figure()
    ax1 = fig.add_subplot(311)
    perf['portfolio_value'].plot(ax=ax1)
    ax1.set_ylabel("Portfolio value (USD)")

    plt.show()
    #Use PyFolio to generate a performance report
    returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
    pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
                          live_start_date=live_start_date, round_trips=True)
In [52]:
algo3_mean_rev_results = run_algorithm(
    start=start,
    end=end,
    initialize=initialize_mean_reversion, analyze=analyze,
    capital_base=10000,
    data_frequency='daily',
    bundle='quandl'
)
No description has been provided for this image
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '2.863%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-1.88%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-0.067%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
Start date1998-01-02
End date2018-12-31
In-sample months97
Out-of-sample months154
In-sample Out-of-sample All
Annual return 2.863% -1.88% -0.067%
Cumulative returns 25.803% -21.616% -1.39%
Annual volatility 15.606% 10.316% 12.633%
Sharpe ratio 0.26 -0.13 0.06
Calmar ratio 0.11 -0.06 -0.00
Stability 0.46 0.37 0.09
Max drawdown -26.336% -29.731% -39.361%
Omega ratio 1.05 0.97 1.01
Sortino ratio 0.36 -0.20 0.08
Skew -1.24 1.19 -0.49
Kurtosis 20.91 21.59 25.20
Tail ratio 1.07 1.10 1.05
Daily value at risk -1.95% -1.305% -1.589%
Gross leverage 0.57 0.59 0.59
Daily turnover 22.499% 19.64% 20.791%
Worst drawdown periods Net drawdown in % Peak date Valley date Recovery date Duration
0 39.36 2003-03-13 2008-10-09 NaT NaN
1 26.34 2000-06-27 2000-10-12 2002-03-25 455
2 19.52 1998-01-02 1998-08-21 1998-10-13 203
3 14.28 1999-10-19 1999-12-07 2000-04-28 139
4 9.97 2002-06-05 2002-07-22 2002-08-28 61
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\matplotlib\dates.py:449: UserWarning: no explicit representation of timezones available for np.datetime64
  d = d.astype('datetime64[us]')
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
  ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
Stress Events mean min max
Dotcom -0.00% -3.68% 2.98%
Lehman -0.13% -3.37% 2.61%
9/11 -0.12% -2.99% 2.66%
US downgrade/European Debt Crisis 0.19% -3.08% 2.56%
Fukushima 0.07% -0.63% 1.23%
US Housing 0.06% -1.84% 2.03%
EZB IR Event -0.03% -0.82% 0.82%
Aug07 -0.13% -3.68% 2.09%
Mar08 -0.23% -1.89% 1.25%
Sept08 -0.31% -3.37% 2.61%
2009Q1 0.20% -2.31% 2.25%
2009Q2 -0.03% -1.71% 2.71%
Flash Crash -0.01% -0.60% 0.50%
Apr14 -0.09% -1.49% 0.50%
Oct14 0.06% -0.83% 1.47%
Fall2015 -0.01% -2.97% 3.48%
Low Volatility Bull Market 0.00% -2.32% 3.22%
GFC Crash -0.00% -5.80% 9.14%
Recovery -0.00% -3.08% 2.56%
New Normal -0.01% -3.41% 3.48%
Top 10 long positions of all time max
sid
AAPL 29.22%
WMT 28.38%
XOM 27.64%
Top 10 short positions of all time max
sid
AAPL -31.20%
XOM -28.74%
WMT -28.70%
Top 10 positions of all time max
sid
AAPL 31.20%
XOM 28.74%
WMT 28.70%
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:317: RuntimeWarning: divide by zero encountered in divide
  ending_price = ending_val / ending_amount
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn("Negative price detected, ignoring for" "round-trip.")
Summary stats All trades Short trades Long trades
Total number of round_trips 2034.00 1330.00 704.00
Percent profitable 0.43 0.32 0.63
Winning round_trips 870.00 428.00 442.00
Losing round_trips 1164.00 902.00 262.00
Even round_trips 0.00 0.00 0.00
PnL stats All trades Short trades Long trades
Total profit $-331.16 $-444.28 $113.12
Gross profit $111328.58 $29710.70 $81617.88
Gross loss $-111659.74 $-30154.98 $-81504.76
Profit factor $1.00 $0.99 $1.00
Avg. trade net profit $-0.16 $-0.33 $0.16
Avg. winning trade $127.96 $69.42 $184.66
Avg. losing trade $-95.93 $-33.43 $-311.09
Ratio Avg. Win:Avg. Loss $1.33 $2.08 $0.59
Largest winning trade $2210.67 $673.43 $2210.67
Largest losing trade $-14455.18 $-699.06 $-14455.18
Duration stats All trades Short trades Long trades
Avg duration 30 days 12:37:08.319075712 21 days 14:13:10.375939849 47 days 09:39:48.069602272
Median duration 16 days 00:00:00 16 days 00:00:00 15 days 00:00:00
Longest duration 418 days 00:00:00 186 days 01:00:00 418 days 00:00:00
Shortest duration 0 days 21:00:00 0 days 21:00:00 1 days 00:00:00
Return stats All trades Short trades Long trades
Avg returns all round_trips -0.02% -0.01% -0.03%
Avg returns winning 1.09% 0.59% 1.56%
Avg returns losing -0.83% -0.28% -2.76%
Median returns all round_trips -0.01% -0.02% 0.12%
Median returns winning 0.50% 0.38% 0.61%
Median returns losing -0.06% -0.05% -0.24%
Largest winning trade 18.52% 5.73% 18.52%
Largest losing trade -144.94% -6.31% -144.94%
Symbol stats AAPL WMT XOM
Avg returns all round_trips -0.09% 0.03% 0.01%
Avg returns winning 2.09% 0.58% 0.49%
Avg returns losing -1.90% -0.29% -0.37%
Median returns all round_trips -0.01% -0.02% -0.01%
Median returns winning 0.99% 0.46% 0.24%
Median returns losing -0.09% -0.05% -0.06%
Largest winning trade 18.52% 2.99% 5.73%
Largest losing trade -144.94% -4.21% -12.41%
Profitability (PnL / PnL total) per name
symbol
AAPL 1324.83%
XOM -127.54%
WMT -1097.29%
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [53]:
def initialize_regime_switch(context):
    context.universe = [symbol(s) for s in tickers]
    context.market_asset = symbol("BRK_A")
    context.vol_lookback = 30
    context.breakout_window = 60
    context.stable_vol = 0.012
    context.breakout_return = 0.04
    context.breakout_buffer = 0.002
    context.crisis_vol = 0.035
    context.crisis_drawdown = -0.15
    context.momentum_lookback = 90
    context.momentum_top_n = 8
    context.momentum_alloc = 1.0
    context.mr_lookback = 20
    context.mr_entry = 1.0
    context.mr_exit = 0.25
    context.mr_long_alloc = 0.45
    context.mr_short_alloc = 0.45
    context.market_history_window = context.vol_lookback + context.breakout_window + 1
    context.min_history = max(
        context.market_history_window,
        context.momentum_lookback + 1,
        context.mr_lookback
    )
    context.regime_codes = {"crisis": -1, "mean_reversion": 0, "momentum": 1}
    context.current_regime = "neutral"

    set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1.0))
    set_slippage(slippage.VolumeShareSlippage())

    schedule_function(regime_rebalance, date_rules.every_day(), time_rules.market_close())


def regime_rebalance(context, data):
    regime, realized_vol, drawdown = detect_regime(context, data)
    if regime is None:
        return

    context.current_regime = regime

    if realized_vol is not None and drawdown is not None:
        record(
            regime_code=context.regime_codes.get(regime, 0),
            realized_vol=realized_vol,
            drawdown=drawdown
        )

    if regime == "crisis":
        liquidate_universe(context, data)
    elif regime == "momentum":
        apply_momentum(context, data)
    else:
        apply_mean_reversion(context, data)


def detect_regime(context, data):
    try:
        prices = data.history(
            context.market_asset,
            "close",
            context.market_history_window,
            "1d"
        ).dropna()
    except Exception:
        return None, None, None

    if len(prices) < context.market_history_window:
        return None, None, None

    recent_returns = prices.pct_change().dropna().iloc[-context.vol_lookback:]
    if recent_returns.empty:
        return None, None, None

    realized_vol = float(recent_returns.std())
    drawdown_window = prices.iloc[-context.vol_lookback:]
    drawdown = float(drawdown_window.iloc[-1] / drawdown_window.max() - 1)
    window_return = float(prices.iloc[-1] / prices.iloc[-context.breakout_window] - 1)
    breakout_high = float(prices.iloc[-context.breakout_window:].max())
    breakout_condition = prices.iloc[-1] >= breakout_high * (1 - context.breakout_buffer)

    if drawdown <= context.crisis_drawdown or realized_vol >= context.crisis_vol:
        return "crisis", realized_vol, drawdown
    if realized_vol <= context.stable_vol:
        return "mean_reversion", realized_vol, drawdown
    if breakout_condition and window_return >= context.breakout_return:
        return "momentum", realized_vol, drawdown
    return "mean_reversion", realized_vol, drawdown


def apply_momentum(context, data):
    try:
        price_history = data.history(
            context.universe,
            "close",
            context.momentum_lookback + 1,
            "1d"
        ).dropna()
    except Exception:
        return

    if len(price_history) < context.momentum_lookback + 1:
        return

    momentum_scores = price_history.iloc[-1] / price_history.iloc[0] - 1
    momentum_scores = momentum_scores.dropna().sort_values(ascending=False)

    if momentum_scores.empty:
        liquidate_universe(context, data)
        return

    selected = momentum_scores.head(context.momentum_top_n)
    target_weights = {}
    if not selected.empty:
        weight = context.momentum_alloc / len(selected)
        for asset in selected.index:
            target_weights[asset] = weight

    apply_target_weights(context, data, target_weights)


def apply_mean_reversion(context, data):
    try:
        price_history = data.history(
            context.universe,
            "close",
            context.mr_lookback,
            "1d"
        ).dropna()
    except Exception:
        return

    if len(price_history) < context.mr_lookback:
        return

    means = price_history.mean()
    stds = price_history.std().replace(0, pd.NA)
    z_scores = ((price_history.iloc[-1] - means) / stds).dropna()

    if z_scores.empty:
        liquidate_universe(context, data)
        return

    long_candidates = z_scores[z_scores <= -context.mr_entry].sort_values()
    short_candidates = z_scores[z_scores >= context.mr_entry].sort_values(ascending=False)
    flat_candidates = z_scores[(z_scores.abs() < context.mr_exit)].index

    target_weights = {}

    if len(long_candidates) > 0 and context.mr_long_alloc > 0:
        weight = context.mr_long_alloc / len(long_candidates)
        for asset in long_candidates.index:
            target_weights[asset] = weight

    if len(short_candidates) > 0 and context.mr_short_alloc > 0:
        weight = context.mr_short_alloc / len(short_candidates)
        for asset in short_candidates.index:
            target_weights[asset] = -weight

    for asset in flat_candidates:
        target_weights.setdefault(asset, 0.0)

    apply_target_weights(context, data, target_weights)


def liquidate_universe(context, data):
    for asset in context.universe:
        if data.can_trade(asset):
            order_target_percent(asset, 0.0)


def apply_target_weights(context, data, target_weights):
    for asset in context.universe:
        weight = target_weights.get(asset, 0.0)
        if data.can_trade(asset):
            order_target_percent(asset, weight)


def handle_data_regime(context, data):
    pass


def analyze_regime(context, perf):
    fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True)
    perf["portfolio_value"].plot(ax=axes[0], label="Equity Curve", linewidth=2.0)
    axes[0].set_title("Regime-Switching Strategy")
    axes[0].legend()
    axes[0].grid(False)

    if "returns" in perf:
        cumulative = (1.0 + perf["returns"]).cumprod() - 1.0
        cumulative.plot(ax=axes[1], label="Cumulative Return")
        axes[1].set_ylabel("Cumulative Return")
        axes[1].legend()
        axes[1].grid(True)

    plt.tight_layout()

    returns, positions, transactions = pf.utils.extract_rets_pos_txn_from_zipline(perf)
    pf.create_full_tear_sheet(returns, positions=positions, transactions=transactions,
                          live_start_date=live_start_date, round_trips=True)
In [54]:
algo4_regime_results = run_algorithm(
    start=start,
    end=end,
    initialize=initialize_regime_switch,
    handle_data=handle_data_regime,
    analyze=analyze_regime,
    capital_base=10000,
    data_frequency="daily",
    bundle="quandl"
)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-1.38%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-4.798%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:670: FutureWarning: Setting an item of incompatible dtype is deprecated and will raise an error in a future version of pandas. Value '-3.487%' has dtype incompatible with float64, please explicitly cast to a compatible dtype first.
  perf_stats.loc[stat, column] = str(np.round(value * 100, 3)) + "%"
Start date1998-01-02
End date2018-12-31
In-sample months97
Out-of-sample months154
In-sample Out-of-sample All
Annual return -1.38% -4.798% -3.487%
Cumulative returns -10.686% -46.796% -52.482%
Annual volatility 16.809% 9.048% 12.636%
Sharpe ratio 0.00 -0.50 -0.22
Calmar ratio -0.04 -0.09 -0.05
Stability 0.12 0.90 0.90
Max drawdown -38.939% -52.126% -67.478%
Omega ratio 1.00 0.91 0.96
Sortino ratio 0.00 -0.71 -0.30
Skew -1.08 0.19 -0.92
Kurtosis 16.25 5.17 21.62
Tail ratio 1.04 1.05 1.04
Daily value at risk -2.118% -1.158% -1.603%
Gross leverage 0.57 0.55 0.56
Daily turnover 54.476% 47.458% 50.266%
Worst drawdown periods Net drawdown in % Peak date Valley date Recovery date Duration
0 67.48 1999-07-16 2018-01-23 NaT NaN
1 15.44 1998-01-02 1998-03-19 1998-10-09 201
2 5.12 1999-02-12 1999-03-11 1999-04-21 49
3 5.00 1998-12-11 1998-12-29 1999-01-15 26
4 4.39 1999-04-29 1999-05-04 1999-05-11 9
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:850: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  starting_value=is_cum_returns[-1],
c:\AJ_MSDS\.venv\Lib\site-packages\matplotlib\dates.py:449: UserWarning: no explicit representation of timezones available for np.datetime64
  d = d.astype('datetime64[us]')
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1407: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
  ax.set_xticklabels(["Daily", "Weekly", "Monthly"])
Stress Events mean min max
Dotcom -0.09% -3.72% 2.87%
Lehman -0.22% -3.28% 2.34%
9/11 0.01% -3.44% 3.76%
US downgrade/European Debt Crisis 0.22% -2.23% 1.87%
Fukushima 0.07% -1.14% 1.19%
US Housing 0.00% -1.14% 1.21%
EZB IR Event -0.01% -0.96% 0.68%
Aug07 0.09% -1.84% 1.31%
Mar08 -0.29% -2.16% 2.25%
Sept08 -0.50% -3.28% 2.34%
2009Q1 -0.02% -1.56% 1.92%
2009Q2 0.04% -1.22% 1.78%
Flash Crash -0.16% -1.52% 0.60%
Apr14 -0.03% -0.72% 0.66%
Oct14 -0.11% -0.80% 0.85%
Fall2015 -0.04% -1.63% 2.03%
Low Volatility Bull Market -0.01% -2.67% 3.04%
GFC Crash -0.05% -3.28% 2.85%
Recovery -0.01% -2.54% 2.49%
New Normal -0.02% -3.29% 3.81%
Top 10 long positions of all time max
sid
XOM 49.12%
AAPL 47.68%
WMT 47.23%
Top 10 short positions of all time max
sid
AAPL -58.56%
XOM -51.48%
WMT -50.50%
Top 10 positions of all time max
sid
AAPL 58.56%
XOM 51.48%
WMT 50.50%
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:100: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  longs = expos.where(expos.applymap(lambda x: x > 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\pos.py:101: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.
  shorts = expos.where(expos.applymap(lambda x: x < 0))
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:323: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_holdings_by_month = df_holdings.resample("1M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\plotting.py:1465: FutureWarning: 'M' is deprecated and will be removed in a future version, please use 'ME' instead.
  df_turnover_by_month = df_turnover.resample("M").mean()
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:317: RuntimeWarning: divide by zero encountered in divide
  ending_price = ending_val / ending_amount
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:139: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  grouped_price = t.groupby(["block_dir", "block_time"]).apply(vwap)
c:\AJ_MSDS\.venv\Lib\site-packages\pyfolio\round_trips.py:214: UserWarning: Negative price detected, ignoring forround-trip.
  warnings.warn("Negative price detected, ignoring for" "round-trip.")
Summary stats All trades Short trades Long trades
Total number of round_trips 3331.00 1903.00 1428.00
Percent profitable 0.51 0.43 0.61
Winning round_trips 1693.00 817.00 876.00
Losing round_trips 1638.00 1086.00 552.00
Even round_trips 0.00 0.00 0.00
PnL stats All trades Short trades Long trades
Total profit $-2849.15 $-3464.64 $615.49
Gross profit $121297.72 $39253.74 $82043.98
Gross loss $-124146.87 $-42718.38 $-81428.50
Profit factor $0.98 $0.92 $1.01
Avg. trade net profit $-0.86 $-1.82 $0.43
Avg. winning trade $71.65 $48.05 $93.66
Avg. losing trade $-75.79 $-39.34 $-147.52
Ratio Avg. Win:Avg. Loss $0.95 $1.22 $0.63
Largest winning trade $1338.90 $1338.90 $889.30
Largest losing trade $-12637.90 $-712.75 $-12637.90
Duration stats All trades Short trades Long trades
Avg duration 20 days 04:51:43.933053137 13 days 22:24:09.080399369 28 days 13:22:11.093137255
Median duration 8 days 03:00:00 8 days 00:00:00 9 days 00:00:00
Longest duration 288 days 00:00:00 178 days 00:00:00 288 days 00:00:00
Shortest duration 0 days 21:00:00 0 days 21:00:00 1 days 00:00:00
Return stats All trades Short trades Long trades
Avg returns all round_trips -0.03% -0.02% -0.04%
Avg returns winning 0.96% 0.56% 1.33%
Avg returns losing -1.03% -0.44% -2.26%
Median returns all round_trips 0.00% -0.02% 0.13%
Median returns winning 0.46% 0.33% 0.67%
Median returns losing -0.22% -0.20% -0.28%
Largest winning trade 15.00% 11.58% 15.00%
Largest losing trade -231.72% -5.84% -231.72%
Symbol stats AAPL WMT XOM
Avg returns all round_trips -0.11% 0.03% 0.01%
Avg returns winning 1.61% 0.43% 0.60%
Avg returns losing -2.46% -0.29% -0.54%
Median returns all round_trips 0.10% -0.01% -0.01%
Median returns winning 0.93% 0.25% 0.39%
Median returns losing -0.32% -0.14% -0.25%
Largest winning trade 15.00% 3.12% 4.08%
Largest losing trade -231.72% -2.92% -22.41%
Profitability (PnL / PnL total) per name
symbol
AAPL 218.80%
XOM 39.79%
WMT -158.59%
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
No description has been provided for this image
In [60]:
import numpy as np
import yfinance as yf
import empyrical as ep

def sanitize_series(series):
    series = series.copy()
    if getattr(series.index, "tz", None) is not None:
        series.index = series.index.tz_convert("UTC").tz_localize(None)
    return series.sort_index().dropna()

strategy_returns = {
    "Monthly_Momentum": sanitize_series(algo1_momentum_results["returns"]),
    "Dual_MA": sanitize_series(algo2_dma_results["returns"]),
    "Mean_Reversion": sanitize_series(algo3_mean_rev_results["returns"]),
    "Regime_Switching": sanitize_series(algo4_regime_results["returns"]),
}

start_date = min(s.index.min() for s in strategy_returns.values())
end_date = max(s.index.max() for s in strategy_returns.values()) + pd.Timedelta(days=1)
bench_tickers = ["SPY", "QQQ", "IEF", "BRK-A"]
bench_prices = yf.download(bench_tickers, start=start_date, end=end_date, auto_adjust=True, progress=False)["Close"]
bench_returns = bench_prices.pct_change().dropna()

def summarize(returns, benchmark):
    aligned = returns.reindex(benchmark.index, method="ffill").dropna()
    bench_aligned = benchmark.loc[aligned.index]
    cumulative = (1 + aligned).prod() - 1
    ann_return = ep.annual_return(aligned)
    ann_vol = ep.annual_volatility(aligned)
    sharpe = ep.sharpe_ratio(aligned)
    mdd = ep.max_drawdown(aligned)
    alpha, beta = ep.alpha_beta(aligned, bench_aligned)
    return pd.Series(
        {
            "Cumulative Return": cumulative,
            "Annual Return": ann_return,
            "Annual Volatility": ann_vol,
            "Sharpe": sharpe,
            "Max Drawdown": mdd,
            "Alpha_vs_SPY": alpha,
            "Beta_vs_SPY": beta,
        }
    )

summary_rows = []
for name, series in strategy_returns.items():
    summary_rows.append(summarize(series, bench_returns["SPY"]))

for ticker in bench_tickers:
    summary_rows.append(
        summarize(
            bench_returns[ticker],
            bench_returns["SPY"],
        ).rename(index=lambda x: x if not x.startswith("Alpha") else x.replace("_vs_SPY", ""))
    )

comparison_df = pd.DataFrame(summary_rows, index=list(strategy_returns.keys()) + bench_tickers)
display(comparison_df.style.format("{:.2%}", subset=["Cumulative Return", "Annual Return", "Annual Volatility", "Max Drawdown"])
                       .format("{:.2f}", subset=["Sharpe", "Alpha_vs_SPY", "Beta_vs_SPY"])
                       .set_caption("Strategy vs Benchmark Performance (Daily Returns)"))
# ...existing code...
Strategy vs Benchmark Performance (Daily Returns)
  Cumulative Return Annual Return Annual Volatility Sharpe Max Drawdown Alpha_vs_SPY Beta_vs_SPY Alpha
Monthly_Momentum 113.21% 4.72% 5.71% 0.84 -11.66% 0.02 0.24 nan
Dual_MA 292.02% 8.68% 16.80% 0.58 -28.03% 0.06 0.44 nan
Mean_Reversion -25.10% -1.75% 10.54% -0.11 -39.36% -0.02 0.10 nan
Regime_Switching -58.81% -5.26% 9.60% -0.52 -64.65% -0.05 0.02 nan
SPY 280.93% 8.49% 18.54% 0.53 -55.19% nan 1.00 0.000000
QQQ 619.01% 12.78% 21.12% 0.68 -53.40% nan 1.03 0.041955
IEF 115.15% 4.78% 6.61% 0.74 -10.40% nan -0.14 0.065040
BRK-A 336.52% 9.40% 20.73% 0.54 -51.47% nan 0.65 0.048488
In [62]:
fig, axes = plt.subplots(len(strategy_returns), 1, figsize=(12, 10), sharex=True)

for ax, (name, series) in zip(axes, strategy_returns.items()):
    aligned = series.align(bench_returns, join="inner")[0]
    ax.plot(aligned.index, aligned, label=name, color="black", alpha=0.6)
    ax.plot(bench_returns.index, bench_returns["SPY"], label="SPY", alpha=0.7)
    ax.plot(bench_returns.index, bench_returns["QQQ"], label="QQQ", alpha=0.7)
    ax.plot(bench_returns.index, bench_returns["IEF"], label="IEF", alpha=0.7)
    ax.plot(bench_returns.index, bench_returns["BRK-A"], label="BRK-A", alpha=0.7)
    ax.set_ylabel("Daily Return")
    ax.legend(loc="upper right")
    ax.grid(True, alpha=0.2)

axes[-1].set_xlabel("Date")
plt.suptitle("Daily Returns: Strategies vs Benchmarks")
plt.tight_layout()
plt.show()
No description has been provided for this image
In [ ]:
fig, axes = plt.subplots(len(strategy_returns), 1, figsize=(12, 10), sharex=True)

for ax, (name, series) in zip(axes, strategy_returns.items()):
    combined = pd.concat(
        [series, bench_returns["SPY"], bench_returns["QQQ"], bench_returns["IEF"], bench_returns["BRK-A"]],
        axis=1,
        keys=[name, "SPY", "QQQ", "IEF", "BRK-A"]
    ).dropna()
    log_curves = np.log1p(combined).cumsum()

    for label in log_curves.columns:
        ax.plot(log_curves.index, log_curves[label], label=label, alpha=0.7)

    ax.set_ylabel("Log cumulative return")
    ax.legend(loc="upper left")
    ax.grid(True, alpha=0.2)

axes[-1].set_xlabel("Date")
plt.suptitle("Log Equity Curves: Strategies vs Benchmarks")
plt.tight_layout()
plt.show()
No description has been provided for this image